
var authCookie = null;
var reconnect = null;

exports.invocar = function(configuracion, params, callbackExito, callbackError) {

    Ti.API.debug("RestClient :: invocar :: iniciamos el metodo con configuracion: " + JSON.stringify(configuracion));

    var Request = require("/utils/remotedata/Request");
    
    Ti.API.debug("RestClient :: invocar :: imports realizados");

	// Establecemos el server al cual dirigir el request, y creamos el request a ejecutar
	Ti.API.debug("RestClient :: invocar :: Construimos un request");
    var server = Alloy.CFG.restUrl;
    var request = new Request(configuracion, params);
    
    Ti.API.debug("RestClient :: invocar :: Request construido. Decidimos que callback de error usar");

	// Decidimos que callback ejecutar en caso de error
	var callbacErrorEfectivo;
	if (callbackError===null || callbackError===undefined) {
	    Ti.API.debug("RestClient :: invocar :: usamos callback por defecto");
		callbackErrorEfectivo = callbackErrorPorDefecto;
	}
	else {
	    Ti.API.debug("RestClient :: invocar :: usamos callback proveido");
		callbackErrorEfectivo = callbackError;
	}
	
	// Decidimos que callback ejecutar en caso de éxito
	Ti.API.debug("RestClient :: invocar :: Decidimos que callback usar como exito");
	var callbackExitoEfectivo;
	if (callbackExito===null || callbackExito===undefined) {
	    Ti.API.debug("RestClient :: invocar :: usamos callback por defecto");
		callbackExitoEfectivo = callbackExitoPorDefecto;
	}
	else {
	    Ti.API.debug("RestClient :: invocar :: usamos callback proveido");
		callbackExitoEfectivo = callbackExito;
	}

    // Decidimos el content type
    var contentType = null;
    if (configuracion.jsonParams !== undefined) {
        contentType = "application/JSON";
    }
    Ti.API.debug("RestClient :: invocar :: Usamos content type : " + contentType);

	// Ejecutamos el request, con los callbacks correspondientes
	Ti.API.debug("RestClient :: invocar :: enviamos el request");
    enviar(server, request, callbackExitoEfectivo, callbackErrorEfectivo, contentType);
    Ti.API.debug("RestClient :: invocar :: request enviado");
};

exports.cleanCookie = function() {
    Ti.API.debug("RestClient :: cleanCookie :: limpiamos la cookie");
    authCookie = null;
    Ti.API.debug("RestClient :: cleanCookie :: fin del limpiado. Valor:" + authCookie);
};

exports.getAuthToken = function() {
   return authCookie;
};

function enviar(server, request, callbackExito, callbackError, contentType) {

    Ti.API.debug("RestClient :: enviar :: inicio de enviar");

    Ti.API.debug("RestClient :: enviar :: verificamos conectividad");

	// Si tenemos conectividad, ejecutamos el request. Sino, indicamos que no hay red.
    if (verificarConectividad()) {

        Ti.API.debug("RestClient :: enviar :: Hay conectividad. Procedemos a realizar el request");

        var xhr = Titanium.Network.createHTTPClient();
        xhr.setTimeout(Alloy.CFG.timeout);
        xhr.setAutoRedirect(false);
        
        Ti.API.debug("RestClient :: enviar :: definimos callback de onload");
        
        function FunctionOnLoad(url){
        	var _url = url;
        	var _dateInit = new Date();
	        return function() {
	        	var _dateFinish = new Date();
	        	var _timeRequest = _dateFinish.getTime() - _dateInit.getTime();
	            Ti.API.info("RestClient[" + _timeRequest + "] " + request.method + ":" + _url);
	            Ti.API.debug("RestClient :: enviar :: callback-onload :: Inicio, obtenemos cookie de sesion");
	            var responseCookie = obtenerCookieDeSesion(this);
	            if (responseCookie !== null) {
	                Ti.API.debug("RestClient :: enviar :: callback-onload :: Cookie encontrada");
	                authCookie = responseCookie;
	            }
	            Ti.API.debug("RestClient :: enviar :: callback-onload :: Parseamos la respuesta: " + this.responseText);
	            var json = JSON.parse(this.responseText);
	            Ti.API.debug("RestClient :: enviar :: callback-onload :: Llamamos el callback de exito");
	            callbackExito(json);
	            Ti.API.debug("RestClient :: enviar :: callback-onload :: callback de exito finalizado");
	        };
        }
        
        xhr.onload = new FunctionOnLoad(request.url);
        
        Ti.API.debug("RestClient :: enviar :: definimos callback de onerror");
        
        xhr.onerror = function() {
        	
        	Ti.API.debug("RestClient :: enviar :: callback-onerror :: Inicio con estado :" + this.readyState);
        	
            if (this.readyState > 1) {
         
                Ti.API.debug("RestClient :: enviar :: callback-onerror :: Obtenemos la cookie de sesion");
         
                // Procesamos la cookie de sesión si es que fue adjuntada
            	var responseCookie = obtenerCookieDeSesion(this);
            	if (responseCookie !== null) {
            	    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Encontramos la cookie");
                    authCookie = responseCookie;
                }
            
            	// Procesamos el texto del error
            	var respuesta = {};
                Ti.API.debug("RestClient :: enviar :: callback-onerror :: Tratamos de parsear la respuesta");
                try {
                	Ti.API.debug("RestClient :: enviar :: callback-onerror :: Respuesta: " + this.responseText);
                    respuesta = JSON.parse(this.responseText);
                    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Respuesta parseada: " + JSON.stringify(respuesta));
                }
                catch (err) {
                    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Error al parsear la respuesta");
                    Ti.API.error(err);
                    Ti.API.error('Respuesta:\n'+this.responseText);
                    respuesta.mensaje = L('error_MensajeDesconocido');
                }
                
                Ti.API.debug("RestClient :: enviar :: callback-onerror :: Respuesta parseada. Switch de estado");
                
            	// Decidimos que acción tomar en base al código del error http
            	switch (this.status) {
            		case 500:
            		    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Estado 500. Lanzamos evento");
            		    Ti.App.fireEvent('EventoErrorComunicacion');
            		    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Llamamos al callback");
            			callbackError(respuesta, 'sistema');
            			Ti.API.debug("RestClient :: enviar :: callback-onerror :: Callback llamado");
            			break;
            		case 400:
            		    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Estado 400. LLamamos al callback");
            			callbackError(respuesta, 'negocio'); // El evento de error es lanzado por el callback
            			Ti.API.debug("RestClient :: enviar :: callback-onerror :: Callback llamado");
            			break;
            		case 401:
            		    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Estado 401. Limpiamos la cookie");
            		    exports.cleanCookie();
            		    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Lanzamos eventos");
            		    Ti.App.fireEvent('EventoErrorComunicacion');
            			Ti.App.fireEvent('LoginNecesario');
            			//callbackError(respuesta, 'login'); // El evento de error es lanzado por el callback
            			if( reconnect != null ){
	            			reconnect(server, request, callbackExito, callbackError, contentType, enviar);
            			} else{
							callbackError(respuesta, 'login'); // El evento de error es lanzado por el callback
            			}
            			Ti.API.debug("RestClient :: enviar :: callback-onerror :: Eventos lanzados");
            			break;
            		default:
            		    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Estado no contemplado: " + this.status);
            		    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Lanzamos eventos");
            		    Ti.App.fireEvent('EventoErrorComunicacion');
            		    Ti.API.debug("RestClient :: enviar :: callback-onerror :: Llamamos al callback");
            			callbackError({mensaje:L('error_MensajeDesconocido')}, 'general');
            			Ti.API.debug("RestClient :: enviar :: callback-onerror :: Callback llamado");
            	};
            	
            	Ti.API.debug("RestClient :: enviar :: callback-onerror :: Fin del switch");
                
            }
            else {
                Ti.API.debug("RestClient :: enviar :: callback-onerror :: Fallo el request. Programamos evento");
                setTimeout(function() {
                    Ti.API.debug("RestClient :: enviar :: callback-onerror :: callback-fallo :: Lanzamos evento");
                    Ti.App.fireEvent('EventoErrorComunicacion');
                    Ti.API.error('Error en el request');
                    Ti.API.debug("RestClient :: enviar :: callback-onerror :: callback-fallo :: LLamamos al callback");
                    callbackError({mensaje:L('error_MensajeDesconocido')}, 'general');
                    Ti.API.debug("RestClient :: enviar :: callback-onerror :: callback-fallo :: Callback llamado");
                }, 3000);
            }
            
        };

        Ti.API.debug("RestClient :: enviar :: Abrimos la conexion");
		// Definimos la URL, y abrimos la conexion
		var url = server + request.url;
		Ti.API.debug("RestClient :: enviar :: Llamando a url: " + url + "  metodo: " + request.method);
        xhr.open(request.method, url);

		// Adjuntamos la cookie de sesión, si es que tenemos una
        if (authCookie!==null) {
            Ti.API.debug("RestClient :: enviar :: adjuntamos la cookie: " + authCookie);
            adjuntarCookieDeSesion(xhr, authCookie);
        }

		// Seteamos el content type si se especificó uno
		if (contentType !== null && contentType !== undefined) {
		    Ti.API.debug("RestClient :: enviar :: Seteamos el content type");
           xhr.setRequestHeader("Content-Type", contentType);
        }
        
        // Seteamos los parametros de header del request
		if ( typeof (request.headers) != 'undefined' && typeof (request.headers.length) != 'undefined') {
            for (var i = 0; i < request.headers.length; i++) {
            	var header = request.headers[i];
	            xhr.setRequestHeader(header.name, header.value);
		    }
        }

		// Ejecutamos el request en base al tipo de request
        if (request.method == "GET" || request.method == "DELETE") {
            Ti.API.debug("RestClient :: enviar :: Enviamos get o delete");
            xhr.send();
        }
        else if (request.method == "POST" || request.method == "PUT") {
            Ti.API.debug("RestClient :: enviar :: enviamos post o put");
            xhr.send(request.body);
        }
        else {
            Ti.API.debug("RestClient :: enviar :: No soportamos el metodo http especificado");
            Ti.API.error('Método inválido: ' + request.method);
            Ti.API.debug("RestClient :: enviar :: Largamos eventos");
            Ti.App.fireEvent('EventoErrorComunicacion');
            Ti.App.fireEvent('ErrorDesconocido');
            Ti.API.debug("RestClient :: enviar :: eventos largados");
        }
        
    }
    else {
        Ti.API.debug("RestClient :: enviar :: no hay conectividad. Lanzamos eventos");
        Ti.App.fireEvent('EventoErrorComunicacion');
    	Ti.App.fireEvent('ErrorGeneral',{'mensaje':L('error_MensajeSinConexion')});
    	Ti.API.debug("RestClient :: enviar :: eventos lanzados");
    }
    
    Ti.API.debug("RestClient :: enviar :: Fin del enviar");
    
}


function verificarConectividad() {
    return Titanium.Network.online;
}


function stringifyRecursive(o) {
    if (o == null)
        return "null";
    var s = '{';
    for (var a in o) {
        if ( typeof o[a] == 'object') {
            s += a + ":" + stringifyRecursive(o[a]);
        } else {
            s += (s != "{") ? "," : "";
            if ( typeof o[a] == 'function') {
                s += a + ':' + 'function()';
            } else {
                s += a + ':' + o[a];
            }
        }
    }
    s += "}";
    return s;
}

function callbackErrorPorDefecto(respuesta) {
    Ti.API.debug("RestClient :: callbackErrorPorDefecto :: Lanzamos evento");
	Ti.App.fireEvent('EventoErrorComunicacion', respuesta);
	Ti.API.debug("RestClient :: callbackErrorPorDefecto :: Fin del callback");
}

function callbackExitoPorDefecto(respuesta) {
    Ti.API.debug("RestClient :: callbackExitoPorDefecto :: Lanzamos evento");
	Ti.API.debug('No se está utilizando la respuesta:');
	Ti.API.debug(stringifyRecursive(respuesta));
	Ti.API.debug("RestClient :: callbackExitoPorDefecto :: Fin del callback");
}

function obtenerCookieDeSesion(respuesta) {
    
    // Obtenemos el header de cookie
    var cookiesHeader = respuesta.getResponseHeader('Set-Cookie');
    Ti.API.debug('Cookie de sesion candidata: ' + JSON.stringify(cookiesHeader));
    
    var cookieParams = [];
    var shouldSaveCookie = false;
    
    if (cookiesHeader !== null && cookiesHeader !== undefined && cookiesHeader != '') {
        
        var individualParts = cookiesHeader.split(';');
        for (var i=0; i<individualParts.length; i++) {
            var pairValues = individualParts[i].trim().split('=');
            if (pairValues.length === 2) {
            	if (pairValues[0] === Alloy.CFG.cookie) {
            		shouldSaveCookie = true;
            	}
            	
            	cookieParams.push(individualParts[i]);
            }
        }
    }
    
    if (shouldSaveCookie) {
        Ti.API.debug('Cookie de sesion encontrada!. String: ');
        return cookieParams.join(';');
    }
    else {
        Ti.API.debug('No se encotró la cookie de sesión');
        return null;
    }
}


function adjuntarCookieDeSesion(httpClient, cookieValue) {
	
    var cookieDeSesion = cookieValue;
    Ti.API.debug('Adjuntamos la cookie: ' + cookieDeSesion); // TODO - Ver si se puede remover este codigo en la release (automaticamente)
    
    var cookieParams = cookieDeSesion.split(';');
    for (var i=0; i < cookieParams.length; i++) {
      	cookieParam = cookieParams[i];
      	httpClient.setRequestHeader('Cookie', cookieParam);
    }
}

exports.setReconnect = function(reconnectFunction) {
	reconnect = reconnectFunction;
};
